package com.chencq.annotation.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.chencq.annotation.WebInitParam;
import com.chencq.annotation.WebServlet;
import com.chencq.annotation.util.ScanClassUtil;
import com.chencq.util.ClassReflectUtil;

/**
 * 使用Filter作为注解的处理器
 *
 */
public class AnnotationHandleFilter implements Filter {

	private static final Logger  LOGGER=LoggerFactory.getLogger(AnnotationHandleFilter.class);
	 
	private ServletContext servletContext = null;
	private static final String SERVLETCLASSMAP = "servletClassMap"; 

	/*
	 * (non-Javadoc) 过滤器初始化时扫描指定的包下面使用了WebServlet注解的那些类
	 * 
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	public void init(FilterConfig filterConfig) throws ServletException {
		LOGGER.info("---AnnotationHandleFilter过滤器初始化开始---");
		servletContext = filterConfig.getServletContext();
		Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
		// 获取web.xml中配置的要扫描的包
		String basePackage = filterConfig.getInitParameter("basePackage");
		// 如果配置了多个包，用逗号分隔
		if (basePackage.indexOf(",") > 0) {
			// 按逗号进行分隔
			String[] packageNameArr = basePackage.split(",");
			for (String packageName : packageNameArr) {
				addServletClassToServletContext(packageName, classMap);
			}
		} else {
			addServletClassToServletContext(basePackage, classMap);
		}
		LOGGER.info("----AnnotationHandleFilter过滤器初始化结束---");
	}

	/**
	 * @Method: addServletClassToServletContext
	 * @Description:添加ServletClass到ServletContext中
	 * @param packageName
	 * @param classMap
	 */
	private void addServletClassToServletContext(String packageName, Map<String, Class<?>> classMap) {
		Set<Class<?>> setClasses = ScanClassUtil.getClasses(packageName);
		for (Class<?> clazz : setClasses) {
			if (clazz.isAnnotationPresent(WebServlet.class)) {
				// 获取WebServlet这个Annotation的实例
				WebServlet annotationInstance = clazz.getAnnotation(WebServlet.class);
				// 获取Annotation的实例的value属性的值
				String annotationAttrValue = annotationInstance.value();
				if (!annotationAttrValue.equals("")) {
					classMap.put(annotationAttrValue, clazz);
				}
				// 获取Annotation的实例的urlPatterns属性的值
				String[] urlPatterns = annotationInstance.urlPatterns();
				for (String urlPattern : urlPatterns) {
					classMap.put(urlPattern, clazz);
				}
				servletContext.setAttribute(SERVLETCLASSMAP, classMap);
				LOGGER.info("annotationAttrValue：" + annotationAttrValue);
				String targetClassName = annotationAttrValue.substring(annotationAttrValue.lastIndexOf("/") + 1);
				LOGGER.info("targetClassName：" + targetClassName);
				LOGGER.info(clazz.toString());
			}
		}
	}

	public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
		LOGGER.info("---进入注解处理过滤器---");
		// 将ServletRequest强制转换成HttpServletRequest
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;
		@SuppressWarnings("unchecked")
		Map<String, Class<?>> classMap = (Map<String, Class<?>>) servletContext.getAttribute(SERVLETCLASSMAP);
		// 获取contextPath
		String contextPath = request.getContextPath();
		// 获取用户请求的URI资源
		String uri = request.getRequestURI().trim();
		// 获取要请求的servlet路径
		String requestServletName = null;
		// 获取请求的servlet的方法名称
		String requestMethod = null;

		// 获取用户使用的请求方式
		String requestType = request.getMethod();

		if (uri.indexOf("!") == -1) {// 表示没有指明调用servlet类中的哪个方法，默认获取该类的doPost/doGet
			requestServletName = uri.substring(contextPath.length(), uri.lastIndexOf("."));
		} else {// 指明了调用的方法
			requestServletName = uri.substring(contextPath.length(), uri.indexOf("!"));
			requestMethod = uri.substring(uri.indexOf("!") + 1, uri.indexOf("."));
		}

		LOGGER.info("获取请求servlet的路径" + requestServletName);
		// 获取要使用的类
		Class<?> clazz = classMap.get(requestServletName);
		LOGGER.info("使用类" + clazz);
		// 创建类的实例
		Object obj = null;
		try {
			obj = clazz.newInstance();
		} catch (InstantiationException e1) {
			LOGGER.error("抽象类或接口实例化失败", e1);
		} catch (IllegalAccessException e1) {
			LOGGER.error("抽象类或接口实例化失败", e1);
		}

		LOGGER.info("-------获取初始化参数-------");
		// 获取WebServlet这个Annotation的实例
		WebServlet annotationInstance = clazz.getAnnotation(WebServlet.class);
		// 获取注解上配置的初始化参数数组
		WebInitParam[] initParamArr = annotationInstance.initParams();
		Map<String, String> initParamMap = new HashMap<String, String>();
		for (WebInitParam initParam : initParamArr) {
			initParamMap.put(initParam.paramName(), initParam.paramValue());
		}

		if (!initParamMap.isEmpty()) {
			// 调用Servlet的初始化方法
			LOGGER.info("-------进入servlet的init方法-------");
			try {
				ClassReflectUtil.executeMethod(obj, "init", new Class[] { Map.class }, new Object[] { initParamMap });
			} catch (Exception e1) {
				throw new RuntimeException("servlet进行init失败");
			}
		}

		if (requestMethod != null) {// 有请求调用的方法
			try {
				String result = (String) ClassReflectUtil.executeMethod(obj, requestMethod, new Class[] { HttpServletRequest.class, HttpServletResponse.class }, new Object[] { request, response });
				if (result != null && !result.trim().isEmpty()) {// 如果请求处理方法返回不为空
					int index = result.indexOf(":");// 获取第一个冒号的位置
					if (index == -1) {// 如果没有冒号，使用转发
						request.getRequestDispatcher(result).forward(request, response);
					} else {// 如果存在冒号
						String start = result.substring(0, index);// 分割出前缀
						String path = result.substring(index + 1);// 分割出路径
						if (start.equals("f")) {// 前缀为f表示转发
							request.getRequestDispatcher(path).forward(request, response);
						} else if (start.equals("r")) {// 前缀为r表示重定向
							response.sendRedirect(contextPath + path);
						}
					}
				}
			} catch (Exception e) {
				throw new RuntimeException("您要调用的方法：" + requestMethod + "它不存在！", e);
			}

		} else {// 没有有请求调用的方法，默认查找doPost/doGet
			if (requestType.equalsIgnoreCase("get")) {
				try {
					ClassReflectUtil.executeMethod(obj, "doGet", new Class[] { HttpServletRequest.class, HttpServletResponse.class }, new Object[] { request, response });
				} catch (Exception e) {
					throw new RuntimeException("调用doGet失败", e);
				}
			} else {
				try {
					ClassReflectUtil.executeMethod(obj, "doPost", new Class[] { HttpServletRequest.class, HttpServletResponse.class }, new Object[] { request, response });
				} catch (Exception e) {
					throw new RuntimeException("调用doPost失败", e);
				}
			}
		}
	}

	public void destroy() {

	}

}